<template>
    <div class="content" ref="content" id="content">
        <div class="panel" style="position: absolute;z-index: 99999;">
            <el-button v-if="!isGoBack" type="primary" plain @click="startCruise">开始巡航</el-button>
            <el-button v-if="!isGoBack" type="primary" plain @click="pauseCruise">暂停巡航</el-button>
            <el-button type="primary" v-if="isGoBack || isCruise != ''" plain @click="goBack">返回</el-button>
            <el-button type="primary" plain @click="toggle">全屏</el-button>
        </div>

        <Loading v-if="!loadingPercentage.completed" size="220" color="#03b2c9" :text="loadingPercentage.percentage"
            dot-count="6" />
        <div ref="container" class="three-container"></div>
    </div>
</template>

<script setup name="Three">
import { ref, onMounted, onBeforeUnmount, defineEmits, nextTick } from 'vue'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js';

// 导入后期处理相关
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
import { SMAAPass } from 'three/examples/jsm/postprocessing/SMAAPass.js';
import { FXAAShader } from 'three/examples/jsm/shaders/FXAAShader.js';
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js';
import { CSS2DRenderer, CSS2DObject } from "three/examples/jsm/renderers/CSS2DRenderer.js";
import { OutputPass } from 'three/examples/jsm/postprocessing/OutputPass.js';
import { gsap } from 'gsap';
import * as MeshLine from 'three.meshline';
import { createBoundingPlanes } from '@/utils/three/BoundingPlanesGroup.js';
import Loading from '@/components/Loading';

const emit = defineEmits([''])

const resources = {
    textures: [],
    models: [],
    geometries: [],
    materials: [],
    eventListeners: []
};

// 获取DOM容器
const container = ref(null)
const content = ref(null)

// 声明Three.js相关变量
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000000)
//  , powerPreference: "low-power" 
const renderer = new THREE.WebGLRenderer({ antialias: true, logarithmicDepthBuffer: true })
let controls = null;
let animationId = null;
let composer = null;
let css2Renderer = null;
const gltfGroup = new THREE.Group();
const css2dRendererGroup = new THREE.Group();

//判断是否返回
const isGoBack = ref(false);

// 点击事件监听
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();



const cameraPosition = [0, 170000, 170000];

let mixer = null;

const gltfArray = [
    {
        url: '/model/0.glb',
        labelPosition: [0, 0, 0],
        labelText: '折板絮凝平流沉淀池',
        isBbox: false

    },
    {
        url: '/model/1.glb',
        labelPosition: [0, 0, 0],
        labelText: 'V型滤池',
        isBbox: false

    },
    {
        url: '/model/2.glb',
        labelPosition: [0, 0, 0],
        labelText: '清水池',
        isBbox: false


    },
    {
        url: '/model/3.glb',
        labelPosition: [0, 0, 0],
        labelText: '加氯加药间',
        isBbox: false

    },
    {
        url: '/model/4.glb',
        labelPosition: [0, 0, 0],
        labelText: '排泥池排水池',
        isBbox: false


    },
    {
        url: '/model/5.glb',
        labelPosition: [0, 0, 0],
        labelText: '污泥浓缩池',
        isBbox: false

    },
    {
        url: '/model/6.glb',
        labelPosition: [0, 0, 0],
        labelText: '污泥平衡池',
        isBbox: false

    },
    {
        url: '/model/7.glb',
        labelPosition: [0, 0, 0],
        labelText: '污泥脱水车间',
        isBbox: false


    },
    {
        url: '/model/8.glb',
        labelPosition: [0, 0, 0],
        labelText: '工作管理间',
        isBbox: true

    },
    {
        url: '/model/9.glb',
        labelPosition: [0, 0, 0],
        labelText: '机修间',
        isBbox: true

    },
    {
        url: '/model/10.glb',
        labelPosition: [0, 0, 0],
        labelText: '',
        isBbox: false

    },
    {
        url: '/model/11.glb',
        labelPosition: [0, 0, 0],
        isBbox: false
    },
    {
        url: '/model/12.glb',
        labelPosition: [0, 0, 0],
        labelText: '食堂',
        isBbox: false

    },
]


const hdrloader = new RGBELoader();
let clock = new THREE.Clock();
let animations = null;
let currentAction = null;

let soldierModel = null;

let isCruise = ref('');
let meshLine = null;
// 路径 
const linePoints = [
    new THREE.Vector3(11243.514559254181, 10, -37403.0441243874),
    new THREE.Vector3(11943.211482641676, 10, -7166.144959806716),
    new THREE.Vector3(11377.920372565184, 10, 20825.718509848884),
    new THREE.Vector3(15806.691622552276, 10, 27567.786533016984),
    new THREE.Vector3(55642.3378134771, 10, 27743.20467948575),
]
const curve = new THREE.CatmullRomCurve3(linePoints);

const loadingPercentage = ref({
    percentage: '',
    completed: false
});

const loadingManager = new THREE.LoadingManager(
    () => {
        loadingPercentage.value.completed = true;
        emit('loadingFinish')
        setTimeout(() => {
            gsap.to(camera.position, {
                y: 80000,
                z: 80000,
                duration: 1.5,
            });
        }, 500);
    },
    (url, loaded, total) => {
        loadingPercentage.value.percentage = `加载中..${((loaded / total) * 100).toFixed(2)}%`;

    }
);


const startCruise = () => {
    if (!isCruise.value) {
        // const line = new FiyLine(linePoints);
        // gltfGroup.add(line.mesh);
        // loadModelRen('/public/GLTF(1)/Soldier.glb');
    }

    // let options = {
    //     index:0
    // }
    // gsap.to(options,{
    //     index:1,
    //     duration: 15,
    //     onUpdate: () => {
    //         const position = curve.getPoint(options.index);
    //         position.y = 1000;
    //         camera.position.copy(position);
    //         camera.lookAt(curve.getPoint(options.index + 0.1));
    //     },  
    // })



    isCruise.value = 'start';
}

const pauseCruise = () => {
    isCruise.value = 'pause';
}

// 初始化场景
function initScene() {

    const width = container.value.clientWidth
    const height = container.value.clientHeight
    // 设置相机位置
    camera.position.set(...cameraPosition);

    camera.updateProjectionMatrix();

    renderer.setSize(width, height);
    // 初始化渲染器
    updateRendererSize()
    // renderer.setPixelRatio(window.devicePixelRatio)
    container.value.appendChild(renderer.domElement)
    // 设置全局环境贴图强度
    renderer.toneMappingExposure = 0.3; // 间接控制整体亮度（范围0-2）

    // 初始化后期处理器
    initPostProcessing();

    // 添加轨道控制器
    controls = new OrbitControls(camera, renderer.domElement)
    controls.enableDamping = true

    // // 添加坐标轴辅助
    // const axesHelper = new THREE.AxesHelper(80000)
    // scene.add(axesHelper)
    scene.background = new THREE.Color('#02004d');


    createCSS2DRenderer();


    gltfArray.forEach((item) => {
        const { labelPosition, labelText, url, isBbox } = item;
        loadModel(url, labelText, isBbox);

    });
    loadEnvironment();


    scene.add(gltfGroup);
    scene.add(css2dRendererGroup);
    // container.value.addEventListener('contextmenu', contextmenuEventListener);
    // container.value.addEventListener('click', clickEventListener);



    // createMeshLine();
}

const contextmenuEventListener = (event) => {
    event.preventDefault(); // 阻止默认的右键菜单
    console.log('右键被点击了');
}
// 鼠标点击事件监听
const clickEventListener = (event) => {
    // 1. 获取 container 相对于视口的位置
    const rect = container.value.getBoundingClientRect();

    // 2. 计算鼠标相对于 container 的坐标
    const mouseX = event.clientX - rect.left;
    const mouseY = event.clientY - rect.top;

    // 3. 归一化到 [-1, 1] 的坐标系
    mouse.x = (mouseX / rect.width) * 2 - 1;
    mouse.y = -(mouseY / rect.height) * 2 + 1; // 注意 Y 轴取反（Three.js 坐标系）

    // 4. 执行射线检测
    raycaster.setFromCamera(mouse, camera);
    const intersects = raycaster.intersectObjects(gltfGroup.children);
    console.log("点击的模型：", intersects);

    if (intersects.length > 0 && intersects[0].object.parent.visible == true) {
    }
}

const createMeshLine = () => {
    const uniformPoint = curve.getPoints(1000);
    console.log(uniformPoint);
    const points = [];
    for (let i = 0; i < uniformPoint.length; i++) {
        points.push(uniformPoint[i].x, uniformPoint[i].y, uniformPoint[i].z);
    }
    // 创建几何体
    const geometry = new THREE.BufferGeometry()
    geometry.setAttribute('position', new THREE.Float32BufferAttribute(points, 3))
    // 创建 MeshLine
    const line = new MeshLine.MeshLine()
    line.setGeometry(geometry)


    const texture = new THREE.TextureLoader().load('/n.png');
    texture.wrapS = texture.wrapT = THREE.RepeatWrapping;

    // 创建材质
    const material = new MeshLine.MeshLineMaterial({
        useMap: true,
        color: new THREE.Color(0x00ffff),
        opacity: 1,
        resolution: new THREE.Vector2(
            container.value.clientWidth,
            container.value.clientHeight
        ),
        sizeAttenuation: true,
        lineWidth: 3000.2,
        transparent: true,
        depthTest: false,  // 添加这个参数
        side: THREE.DoubleSide, // 添加这个参数
        map: texture,
        repeat: new THREE.Vector2(1, 1),
        blending: THREE.AdditiveBlending,
        dashOffset: 0 // 虚线偏移量 - 这就是我们要动画化的参数
    })
    // 关键修补：覆盖有问题的着色器代码
    material.onBeforeCompile = (shader) => {
        shader.uniforms.offset = {
            value: new THREE.Vector2(0, 0)
        }
        shader.vertexShader = shader.vertexShader
            .replace(
                'vIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );',
                'vIsPerspective = float( projectionMatrix[2][3] == 0.0 );'
            )
            .replace(
                '#include <common>',
                `#include <common>
          bool isPerspectiveMatrix(mat4 m) {
            return m[2][3] == -1.0;
          }`
            );
        shader.vertexShader = shader.vertexShader.replace(
            'uniform float opacity;',
            `uniform float opacity;
          uniform vec2 offset;`
        ); console.log(shader);
        shader.vertexShader = shader.vertexShader.replace(
            'vUV = uv;',
            `vUV = uv + offset;`
        ); console.log(shader);
    };
    // 创建网格
    meshLine = new THREE.Mesh(line.geometry, material)
    console.log(meshLine);

    scene.add(meshLine)
};

const createLabel = (text) => {
    const label = document.createElement("div");
    label.className = "label";
    label.textContent = text;
    label.style.color = "#02004d";
    label.style.border = "1px solid #37dbed";
    label.style.background = "rgba(55, 219, 237,0.5)";
    label.style.padding = "5px 10px";
    label.style.borderRadius = "5px";
    label.style.cursor = 'pointer';
    label.style.pointerEvents = 'auto';

    return label;
};

const createCSS2DRenderer = () => {
    const width = container.value.clientWidth
    const height = container.value.clientHeight
    // 设置 CSS2D 渲染器
    css2Renderer = new CSS2DRenderer();
    css2Renderer.setSize(width, height);
    css2Renderer.domElement.style.position = 'absolute';
    css2Renderer.domElement.style.top = '0';
    css2Renderer.domElement.style.left = '0';
    css2Renderer.domElement.style.pointerEvents = 'none'; // 防止阻挡交互
    container.value.appendChild(css2Renderer.domElement);
}
// 初始化后期处理
function initPostProcessing() {

    const width = container.value.clientWidth
    const height = container.value.clientHeight
    // 创建效果组合器
    composer = new EffectComposer(renderer);

    // 添加渲染通道
    const renderPass = new RenderPass(scene, camera);
    composer.addPass(renderPass);

    // 根据性能需求选择一种抗锯齿方案

    // 方案1：FXAA (快速近似抗锯齿) - 性能最好
    const fxaaPass = new ShaderPass(FXAAShader);
    const pixelRatio = renderer.getPixelRatio();
    fxaaPass.material.uniforms['resolution'].value.x = 1 / (width * pixelRatio);
    fxaaPass.material.uniforms['resolution'].value.y = 1 / (height * pixelRatio);
    composer.addPass(fxaaPass);

    // 添加OutputPass
    const outputPass = new OutputPass();
    composer.addPass(outputPass);

}
// 处理环境贴图
const loadEnvironment = () => {
    hdrloader.load('/t_env_light.hdr', function (texture) {
        texture.mapping = THREE.EquirectangularReflectionMapping;
        scene.environment = texture;
    });
};
// 设置相机对准的模型
const setCameraTarget = (model) => {
    // 调整相机位置适应模型
    const box = new THREE.Box3().setFromObject(model);
    const center = box.getCenter(new THREE.Vector3());
    const size = box.getSize(new THREE.Vector3());

    const targetPosition = new THREE.Vector3(
        center.x + size.length() * 0.2,
        center.y + size.length() * 0.5,
        center.z + size.length()
    );

    const tl = gsap.timeline();

    // 1. 移动 camera
    tl.to(camera.position, {
        x: targetPosition.x,
        y: targetPosition.y,
        z: targetPosition.z,
        duration: 1.5,
        ease: "power2.inOut",
    });
    // 3. 调整 controls.target（在上一个动画结束后执行）
    tl.to(controls.target, {
        x: center.x,
        y: center.y,
        z: center.z,
        duration: 0.8,
        ease: "power2.inOut",
    }, "<"); // ">" 表示在上一个动画结束后执行

};
const LabelClick = (model, labelText) => {
    setCameraTarget(model);
    gltfGroup.children.forEach((child) => {
        if (child.resetName === labelText) {
            child.visible = true;
        } else {
            child.visible = false;
        }
    });
    css2dRendererGroup.children.forEach((child) => {
        if (child.resetName === labelText) {
            child.visible = true;
        } else {
            child.visible = false;
        }
    });
    isGoBack.value = true;
}

const loadModelRen = (src, labelText) => {
    const loader = new GLTFLoader(loadingManager);
    loader.load(src, (gltf) => {
        const model = gltf.scene;
        animations = gltf.animations;
        model.traverse((item) => {

        });

        // 播放第一个动画
        mixer = new THREE.AnimationMixer(model);
        playAnimation(3);

        model.scale.set(2000, 2000, 2000);
        model.position.set(11243.514559254181, 10, -37403.0441243874);
        scene.add(model);

        soldierModel = model


    })
}
function playAnimation(index, fadeDuration = 0.5) {
    if (!animations[index]) return;

    // 淡出当前动画
    if (currentAction) {
        currentAction.fadeOut(fadeDuration);
    }

    // 创建新动画动作并淡入
    currentAction = mixer.clipAction(animations[index]);
    currentAction
        .reset()
        .setEffectiveTimeScale(1) // 播放速度（1=正常）
        .setEffectiveWeight(1)    // 动画权重（0-1）
        .fadeIn(fadeDuration)
        .play();
}
// 加载模型
function loadModel(src, labelText, isBbox) {
    const loader = new GLTFLoader(loadingManager);
    const dracoLoader = new DRACOLoader();
    dracoLoader.setDecoderPath("/draco/gltf/");
    dracoLoader.setDecoderConfig({ type: "js" });
    loader.setDRACOLoader(dracoLoader);


    loader.load(
        src, // 替换为你的模型路径
        (gltf) => {
            const model = gltf.scene;
            resources.models.push(model);

            if (labelText) {
                const box = new THREE.Box3().setFromObject(model);
                const center = box.getCenter(new THREE.Vector3());
                const div = createLabel(labelText);
                const clickHandler = () => {
                    console.log('标签被点击了！');
                    LabelClick(model, labelText);
                };
                div.addEventListener('click', clickHandler);
                resources.eventListeners.push({ element: div, handler: clickHandler });

                const labelObject = new CSS2DObject(div);
                labelObject.position.set(center.x, center.y + 10000, center.z);
                labelObject.resetName = labelText;
                css2dRendererGroup.add(labelObject); // 标签跟随立方体
                resources.models.push(labelObject);
            }
            if (isBbox) {
                // 计算包围盒（AABB）
                const bbox = new THREE.Box3().setFromObject(model);
                // 3. 创建包围盒平面组
                const boundingPlanes = createBoundingPlanes(bbox);

                // 4. 将组添加到场景
                scene.add(boundingPlanes);
            }



            model.resetName = labelText;
            gltfGroup.add(model);
        },
    )
}
// 更新渲染器尺寸
function updateRendererSize() {
    const width = container.value.clientWidth
    const height = container.value.clientHeight
    camera.aspect = width / height
    camera.updateProjectionMatrix()
    renderer.setSize(width, height)

    // 更新后期处理器
    if (composer) {
        composer.setSize(width, height);

        // 更新FXAA分辨率
        const passes = composer.passes;
        for (let i = 0; i < passes.length; i++) {
            if (passes[i] instanceof ShaderPass && passes[i].material.uniforms['resolution']) {
                const pixelRatio = renderer.getPixelRatio();
                passes[i].material.uniforms['resolution'].value.x = 1 / (width * pixelRatio);
                passes[i].material.uniforms['resolution'].value.y = 1 / (height * pixelRatio);
            }
        }
    }
}



let t = 0; // 参数值
let speed = 0.001; // 移动速度

const goBack = () => {
    isGoBack.value = false;
    isCruise.value = '';
    t = 0;
    gltfGroup.children.forEach((child) => {
        child.visible = true;
    });
    css2dRendererGroup.children.forEach((child) => {
        child.visible = true;
    });
    gsap.to(camera.position, {
        x: 0,
        y: 80000,
        z: 80000,
        duration: 1.5,
        ease: "power2.inOut",
    });
    gsap.to(controls.target, {
        x: 0,
        y: 0,
        z: 0,
        duration: 0.8,
        ease: "power2.inOut",
    }, "<"); // ">" 表示在上一个动画结束后执行
}
// 设置人物移动 相机跟随 模型移动 第三人称
const soldierModelAnimate = () => {
    // 处理人物移动
    if (soldierModel && isCruise.value == 'start') {
        // 1. 更新模型位置
        const uniformPoint = curve.getPointAt(t);
        soldierModel.position.copy(uniformPoint);

        // 2. 计算下一个点的位置用于确定朝向
        const nextT = (t + 0.01) % 1; // 使用一个稍大的t值来计算方向
        const nextPoint = curve.getPointAt(nextT);

        // 3. 计算移动方向向量
        const direction = new THREE.Vector3().subVectors(nextPoint, uniformPoint);

        // 4. 只有当移动距离足够大时才更新旋转（避免抖动）
        if (direction.length() > 0.001) {
            // 让人物朝向移动方向
            soldierModel.lookAt(nextPoint);
            soldierModel.rotation.y -= Math.PI;

            // 如果需要调整初始朝向（如果模型默认朝向不是Z轴正方向）
            // soldierModel.rotateY(Math.PI); // 根据模型初始朝向可能需要调整
        }

        // const cameraOffset = new THREE.Vector3(3000, 2000, -5000); // 相机相对模型的偏移
        // camera.position.copy(soldierModel.position).add(cameraOffset);
        // // camera.lookAt(soldierModel.position);
        controls.target.copy(soldierModel.position);
        let worldPosition = new THREE.Vector3();
        soldierModel.getWorldPosition(worldPosition);
        camera.lookAt(worldPosition.clone());
        controls.target.copy(worldPosition.clone());
        let newP = worldPosition.clone().add(new THREE.Vector3(-0, 9000, -5000));
        let oldCP = camera.position.clone();
        gsap.to(oldCP, {
            x: newP.x,
            y: newP.y,
            z: newP.z,
            duration: 0.5,
            ease: 'none',
            onUpdate() {
                camera.position.set(oldCP.x, oldCP.y, oldCP.z);
            }
        })
        // 5. 更新进度
        t = (t + speed) % 1;
    }
}
// 动画控制参数
const pathParams = {
    t: 0,          // 当前路径进度 (0-1)
    lookAhead: 0.05, // 朝向提前量（控制看向多远的下一个点）
    speed: 0.0005    // 移动速度
};


// 相机沿路径移动函数
const animateCamera = () => {
    // 1. 计算当前点和下一个目标点
    const currentPoint = curve.getPointAt(pathParams.t);
    const targetT = (pathParams.t + pathParams.lookAhead) % 1;
    const targetPoint = curve.getPointAt(targetT);


    gsap.to(camera.position, {
        x: currentPoint.x,
        y: currentPoint.y + 2000,
        z: currentPoint.z,
        duration: 0.5,
        ease: 'none',
        onUpdate() {
            controls.target.copy(new THREE.Vector3(targetPoint.x, targetPoint.y + 2000, targetPoint.z)); // 关键：看向前方路径点
        }
    })
    // 2. 更新相机位置和朝向

    // 3. 更新进度
    pathParams.t = (pathParams.t + pathParams.speed) % 1;
};

// 动画循环
function animate() {
    // 1. 获取 container 相对于视口的位置
    const rect = container.value?.getBoundingClientRect();
    // renderer.render(scene, camera)
    if (rect) {
        renderer.setSize(rect.width, rect.height);
        camera.aspect = rect.width / rect.height;
        camera.updateProjectionMatrix();

        css2Renderer?.setSize(rect.width, rect.height);
        css2Renderer?.render(scene, camera); // 渲染 CSS2D 标签
    }

    composer?.render();


    const deltaTime = clock.getDelta(); // 获取自上一次调用 getDelta() 的时间差

    // mixer?.update(deltaTime);
    controls?.update()

    if (isCruise.value == 'start') {
        animateCamera();
        // soldierModelAnimate();
    }
    // 更新纹理偏移
    if (meshLine) {
        meshLine.material.uniforms.offset.value.x -= 0.001;
        meshLine.material.uniforms.dashOffset.value -= 0.001;
    }
    requestAnimationFrame(animate)
}

// 窗口大小变化处理
function handleResize() {
    updateRendererSize()

}
import { useFullscreen } from '@vueuse/core'

const { isFullscreen, enter, exit, toggle } = useFullscreen(content);
// 进入全屏模式
function enterFullscreen(element) {
    if (element.requestFullscreen) {
        element.requestFullscreen();
    } else if (element.webkitRequestFullscreen) { // Safari
        element.webkitRequestFullscreen();
    } else if (element.msRequestFullscreen) { // IE11
        element.msRequestFullscreen();
    }
}

onMounted(() => {
    const contentReact = content.value?.getBoundingClientRect();
    if (contentReact?.top) {
        // content.value.style.height = `calc(100vh - ${contentReact?.top}px)`
        initScene()
        animate()
        // 监听窗口变化
        window.addEventListener('resize', handleResize);
    }
    // toggle();
    // autofit.init({
    //     el: '#app',
    // })
})

onBeforeUnmount(() => {
    // 1. 停止所有动画
    cancelAnimationFrame(animationId);
    if (mixer) {
        mixer.stopAllAction();
        mixer.uncacheRoot(scene);
    }

    // 2. 清理场景
    scene.traverse(object => {
        if (!object.isMesh) return;

        if (object.geometry) {
            object.geometry.dispose();
            resources.geometries = resources.geometries.filter(g => g !== object.geometry);
        }

        if (object.material) {
            if (Array.isArray(object.material)) {
                object.material.forEach(m => m.dispose());
            } else {
                object.material.dispose();
            }
            resources.materials = resources.materials.filter(m => m !== object.material);
        }
    });

    // 3. 清理纹理
    resources.textures.forEach(texture => {
        texture.dispose();
        if (texture.image && texture.image.close) {
            texture.image.close();
        }
    });

    // 4. 移除事件监听器
    resources.eventListeners.forEach(({ element, handler }) => {
        if (element && handler) {
            element.removeEventListener('click', handler);
        }
    });

    // 5. 清理渲染器
    renderer.dispose();
    renderer.domElement = null;

    // 6. 清理 CSS2D 渲染器
    if (css2Renderer) {
        container.value?.removeChild(css2Renderer.domElement);
        css2Renderer.domElement = null;
    }

    // 7. 清理控制器
    controls?.dispose();


    // 9. 清理 GSAP
    gsap.globalTimeline.clear();
    gsap.killTweensOf(camera.position);
    gsap.killTweensOf(controls.target);
});
</script>

<style scoped lang="scss">
.three-container {
    width: 100%;
    height: 100%;
    position: relative;
    overflow: hidden;
}

.content {
    width: 100%;
    height: 100%;
    position: relative;
}
</style>